﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace LiteExpress.Utilities
{
    public class IPHelper
    {
        public static string GetClientIP()
        {
            if (HttpContext.Current == null)
            {
                return string.Empty;
            }

            var request = HttpContext.Current.Request;

            string _ClientIPAddress = request.Headers["X-Real-IP"];
            if (string.IsNullOrEmpty(_ClientIPAddress))
            {
                _ClientIPAddress = request.UserHostAddress;
            }
            return _ClientIPAddress;
        }

        public static string GetForwardIPs()
        {
            if (HttpContext.Current == null)
            {
                return string.Empty;
            }

            var request = HttpContext.Current.Request;

            string _ClientIPAddress = request.Headers["X-Forwarded-For"];
            if (string.IsNullOrEmpty(_ClientIPAddress))
            {
                _ClientIPAddress = request.UserHostAddress;
            }
            else
            {
                List<string> iplist = new List<string>();
                var rawlist = _ClientIPAddress.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries);

                foreach (string ip in rawlist)
                {
                    if (IsNativeIP(ip))
                    {
                        continue;
                    }

                    iplist.Add(ip);
                }
                _ClientIPAddress = string.Join(",", iplist);

                if (_ClientIPAddress.Length > 200)//数据库字段设置长度最大200，可容纳12个IP
                {
                    _ClientIPAddress = _ClientIPAddress.Substring(_ClientIPAddress.IndexOf(',', _ClientIPAddress.Length - 200));
                }
            }
            return _ClientIPAddress;
        }

        public static string GetClientPort()
        {
            if (HttpContext.Current == null)
            {
                return string.Empty;
            }

            var request = HttpContext.Current.Request;

            string clientPort = request.ServerVariables["REMOTE_PORT"];
            return clientPort;
        }

        public static bool IsNativeIP(string ip)
        {
            if(ip.StartsWith("10."))
            {
                return true;
            }

            if (ip.StartsWith("192.168."))
            {
                return true;
            }

            if (ip.StartsWith("172."))
            {
                var iplist = ip.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                int ip2 = 0;
                int.TryParse(iplist[1], out ip2);
                if (ip2 >= 16 && ip2 <= 31)
                {
                    return true;
                }
            }

            return false;
        }

        public static long String2Number(string ipStr)
        {
            if (!string.IsNullOrWhiteSpace(ipStr))
            {
                string[] strs = ipStr.Split('.');
                byte[] ipBytes = new byte[strs.Length];
                for (int i = 0; i < strs.Length; i++)
                {
                    byte iIpPart = 0;
                    byte.TryParse(strs[i], out iIpPart);
                    ipBytes[i] = iIpPart;
                }
                return Bytes2Number(ipBytes);
            }
            return 0;
        }

        private static long Bytes2Number(byte[] ipBytes)
        {
            long ret = 0;
            if (ipBytes != null)
            {
                for (int i = 0, len = ipBytes.Length; i < len; i++)
                {
                    ret |= ((long)ipBytes[i]) << (8 * (len - 1 - i));
                }
            }
            return ret;
        }

        public static string Number2String(long ipLong)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append((ipLong >> 24) & 0xFF);
            sb.Append('.');
            sb.Append((ipLong >> 16) & 0xFF);
            sb.Append('.');
            sb.Append((ipLong >> 8) & 0xFF);
            sb.Append('.');
            sb.Append(ipLong & 0xFF);

            return sb.ToString();
        }
    }

    [Serializable]
    public class IPRange
    {
        public string Name { get; set; }
        public long BeginIP { get; set; }
        public long EndIP { get; set; }

        public long Range
        {
            get
            {
                return EndIP - BeginIP;
            }
        }

        public IPRange()
        { 
        }

        public IPRange(string name, string ipBegin, string ipEnd)
        {
            this.Name = name;
            this.BeginIP = IPHelper.String2Number(ipBegin);
            this.EndIP = IPHelper.String2Number(ipEnd);
        }

        public static T Search<T>(IEnumerable<T> IPRangeList, string ipString) where T : IPRange
        {
            if (IPRangeList == null)
            {
                return null;
            }

            long ip = IPHelper.String2Number(ipString);

            foreach (T ir in IPRangeList)
            {
                if (ir.BeginIP <= ip && ir.EndIP >= ip)
                {
                    return ir;
                }
            }

            return null;
        }
    }
}
